# -*- coding: utf-8 -*-
"""
# @created on : 10月 2021/10/21 15:33
# @author     : kevin
# @file       : dubbo_api.py
# @software   : PyCharm
# @project    : auto_interface_test


@license: (C) Copyright 2019-2025, Corporation Limited.
@desc:
"""
import telnetlib
import re
import time
from common.logger import Logger


class TelentClient(object):
    """
    连接telent服务器，并执行shell命令
    """
    def __init__(self, host, port):
        self.log = Logger().logger()
        self.con = telnetlib.Telnet()
        self.server_host = host
        self.server_port = port

    def connect_tel(self):
        """
        尝试连接telnet服务器
        :return: 成功返回True，失败为False
        """
        res = None
        try:
            self.con.open(host=self.server_host, port=self.server_port)
            self.log('info', f'登录{self.server_host}:{self.server_port}成功')
            res = True
        except Exception as e:
            self.log('error', f'连接失败，原因为：{e}')
            res = False
        finally:
            return res

    def exec_command(self, command):
        """
        在telnet下执行命令，并返回执行结果
        :param command:
        :return:
        """
        cmd = f'invoke {command}'
        self.con.write(cmd)
        # 初始化调用次数
        invoke_count = 0
        result = None
        # 循环调用5次，如果某一次成功则不再循环
        for i in range(1, 5):
            # 从socket buffer接受数据，然后从cookedq读取尽可能多的数据
            result = self.con.read_very_eager().decode(encoding='utf-8').split('\r\n')[0]
            if result == '' or result is None:
                time.sleep(1)
                self.log('error', f'调用dubbo接口第{i}次失败')
                invoke_count += 1
            else:
                break
        return result

    # 退出telnet
    def logout(self):
        self.con.write(b'exit\n')
        self.log('info', f'登出{self.server_host}:{self.server_port}成功')


class InvokeDubboApi(object):
    def __init__(self, content):
        self.log = Logger().logger()
        try:
            # 解析dubbo部署的IP和port，虽然这里基本上不需要re来做匹配，但为了严谨还是增加了这部分
            dubbo_address = re.compile(r'([0-9)+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)', re.I)
            result = dubbo_address.search(str(content)).group()
            server_host = result.split(':')[0]
            server_port = result.split(':')[1]
            self.log('info', f'获取到dubbo部署信息：{result}')
        except Exception as e:
            raise Exception(f'获取dubbo部署信息失败，失败原因为：{e}')

        try:
            self.tel_client = TelentClient(server_host, server_port)
            self.login_flg = self.tel_client.connect_tel()
        except Exception as e:
            self.log('error', f'invokedubboapi 初始化失败，失败原因为：{e}')

    # 调用dubbo接口
    def invoke_dubbo_api(self, data):
        cmd = data['dubbo_service'] + '.' + data['dubbo_method'] + data['parameters']
        self.log('info', f'调用命令为：{cmd}')
        res = None
        try:
            if self.login_flg:
                res = self.tel_client.exec_command(cmd)
            else:
                self.log('error', f'登录失败！')
        except Exception as e:
            raise Exception(f'调用接口异常，讲课相应为：{res}，异常信息为：{e}')
        finally:
            self.loggot()
            return res

    # 调用多个dubbo接口（所有接口需要是同一个IP端口下的）
    def invoke_dubbo_apis(self, data):
        result_list = []
        # 针对多接口调用，先分组后再调用，结果组装后返回
        if isinstance(data, list):
            for i in range(len(data)):
                res = self.invoke_dubbo_api(data[i])
                result_list.append({'data': data[i], 'result': res})
            return result_list
        else:
            return f'入参不是list类型，请确认'

    # 退出telent登录
    def loggot(self):
        self.tel_client.logout()


